package com.duoduo.common.api.help;


import com.duoduo.common.api.constants.Constant;
import com.duoduo.common.api.constants.LogConstant;
import com.duoduo.common.api.tuple.Tuple;
import com.duoduo.common.api.tuple.TwoTuple;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.Map.Entry;
import java.util.function.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.stream.Collectors.*;

public class MapInnerUtil {
	
	private static final Logger LOGGER = LoggerFactory.getLogger(MapInnerUtil.class);
	private static final String REGEX_SQUARE_BRACKETS = "\\[(.*?)]";
	private static final Pattern PATTERN = Pattern.compile(REGEX_SQUARE_BRACKETS);
	
	/**根据表达式从map获取值
	 * @param map
	 * @param keys key表达式，例如"data.banner.HSbanner.[0].title", "data.kaiguan.type", "data.MainProduct_internal.ProductAreas.[1].child.[1].img"
	 * @return 多个表达式对应的值，顺序和keys一一对应
	 */
	public static Object[] getValues(Map<Object, Object> map, String[] keys) {
		if(ArrayInnerUtil.isEmpty(keys)){
			return new Object[0];
		}
		Object[] result = new Object[keys.length];
		int size = keys.length;
		for (int i=0; i<size; i++) {
			result[i] = getValue(map, keys[i]);
		}
		return result;
	}
	
	private static Object getValue(Object obj, String keyStr) {
		String[] keyArr = StringUtils.split(keyStr, Constant.DOT);
		int size = keyArr.length;
		Object value = null;
		for (int i=0; i<size; i++) {
			String innerkey = keyArr[i];
			value = innerGetValue(obj, innerkey);
			if(value == null){
				return value;
			}
			obj = value;
		}
		return value;
	}
	
	@SuppressWarnings("rawtypes")
	private static Object innerGetValue(Object obj, String innerkey) {
		if(obj instanceof Map) {
			Map map = (Map)obj;
			return map.get(innerkey);
		}else if(obj instanceof List) {
			List list = (List)obj;
			Matcher matcher = PATTERN.matcher(innerkey);
			if (matcher.find()) {
				int index = -1;
				try{
					index = Integer.parseInt(matcher.group(1));
				}catch(Exception e){
					LOGGER.error(LogConstant.MAP_UTIL + " value is list, key [x], but x is not number", e);
				}
				if(index == -1){
					return null;
				}
				return list.get(index);
			}else{
				LOGGER.error(LogConstant.MAP_UTIL + " value is list, but key is not [x] type");
				return null;
			}
		}else{
			LOGGER.error(LogConstant.MAP_UTIL + " value type is not Map or List");
			return null;
		}
	}
	
	/**根据表达式从map获取值
	 * @param map
	 * @param key key表达式，例如data.banner.HSbanner.[0].title
	 * @param clazz value类型
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T getValue(Map<Object, Object> map, String key, Class<T> clazz) {
		Object result = getValue(map, key);
		return (T)result;
	}

	/**判断是否空map
	 * @param map
	 * @return
	 */
	public static <K, V> boolean isEmpty(Map<K, V> map){
		return map == null || map.isEmpty();
	}

	/**判断是否非空map
	 * @param map
	 * @return
	 */
	public static <K, V> boolean isNotEmpty(Map<K, V> map){
		return map != null && !map.isEmpty();
	}

	/**
	 * map过滤
	 * @param map
	 * @param predicate
	 * @return
	 */
	public static <K, V> Map<K, V> paraFilter(Map<K, V> map, Predicate<? super Entry<K, V>> predicate) {
        Map<K, V> result = new HashMap<>();
        if (map == null || map.size() <= 0) {
            return result;
        }
        return map.entrySet().stream().filter(predicate).collect(Collectors.toMap(e->e.getKey(), e->e.getValue()));
    }

	/**hashMap按key排序，key必须实现Comparable接口
	 * @param param
	 * @return
	 */
	public static <T extends Comparable<? super T>, V> Map<T , V> sortHashMap(Map<T , V> param){
		Map<T , V> myMap = new LinkedHashMap<>();

        List<T> keyList = new ArrayList<T>();
        Iterator<T> it = param.keySet().iterator();
        while(it.hasNext()){
            keyList.add(it.next());
        }
        Collections.sort(keyList);
        Iterator<T> it2 = keyList.iterator();
        while(it2.hasNext()){
            T key = it2.next();
            myMap.put(key, param.get(key));
        }
        return myMap;
	}

	/**
	 * Map转换为键值对
	 * @param map
	 * @param sort
	 * @param ignoreNames
	 * @return
	 */
	public static<T extends Comparable<? super T>, V> String MapToKeyValue(Map<T, V> map, boolean sort, String... ignoreNames){
		StringBuilder keyValue = new StringBuilder();
		Map<T, V> sortedMap = null;
		if(sort){
			sortedMap = sortHashMap(map);
		}else{
			sortedMap = map;
		}
		sortedMap.entrySet().forEach(e -> {
			String key = e.getKey().toString();
			Optional<String> opt = Arrays.stream(ignoreNames).filter(n -> n.equals(key)).findFirst();
			if(!opt.isPresent() && e.getValue() != null){
				keyValue.append(String.format("%1$s=%2$s&",key,e.getValue().toString()));
			}
		});
		if(keyValue.length() > 0){
			return keyValue.toString().substring(0,keyValue.length()-1);
		}
		return keyValue.toString();
	}

	public static<T extends Comparable<? super T>,V> String MapToXml(Map<T, V> map){
		return MapToXml(map, true, false);
	}

	/**
	 *
	 * map转xml
	 * @param map
	 * @param ignoreEmpty
	 * @param skipNamespace
	 * @param ignoreNames
	 * @return
	 */
	public static<T extends Comparable<? super T>,V> String MapToXml(Map<T, V> map, boolean ignoreEmpty, boolean skipNamespace, String... ignoreNames){
		StringBuilder xml = new StringBuilder();
		if(!skipNamespace){
			xml.append("<?xml version='1.0' encoding='UTF-8' standalone='yes' ?><xml>");
		}
		map.entrySet().forEach(e -> {
			String key = e.getKey().toString();
			Optional<String> opt = Arrays.stream(ignoreNames).filter(n->n.equals(key)).findFirst();
			if(!opt.isPresent()){
				if(ignoreEmpty && e.getValue() != null && e.getValue().toString().length() > 0){
					xml.append("<" + key +">" + e.getValue() + "</" + key + ">\n");
				}else if(!ignoreEmpty){
					xml.append("<" + key +">" + e.getValue() + "</" + key + ">\n");
				}
			}
		});
		if(!skipNamespace){
			xml.append("</xml>");
		}
		return xml.toString();
	}

	/**map对象拷贝，其中map的value是基本对象
	 * @param source
	 * @param dest
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	public static <K, V> void copyMap(Map<K, V> source, Map<K, V> dest) {
		if(source==null || source.isEmpty()){
			return;
		}
		if(dest == null){
			dest = new HashMap<>();
		}
		for(Entry<K, V> entry : source.entrySet()){
			dest.put(entry.getKey(), entry.getValue());
		}
	}

	/**map的value转换为List
	 * @param list
	 * @return
	 */
	public static <K, V> List<V> mapValuesToList(Map<K, V> map){
		if(map == null){
			return null;
		}
		return map.values().stream().collect(toList());
	}

	/**map的value转换为List
	 * @param list
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <K, V, Y> List<Y> mapValuesToList2(Map<K, V> map, Class<Y> y){
		if(map == null){
			return null;
		}
		return map.values().stream().map(v -> (Y)v).collect(toList());
	}

	public static <K, V> Map<K, V> streamToMap(Stream<V> stream, Function<? super V, ? extends K> keyMapper, Function<? super V, ? extends V> valueMapper){
		if(stream != null){
			return stream.collect(toMap(keyMapper, valueMapper));
		}
		return null;
	}

	public static <K, V> Map<K, V> listToMap(List<V> list, Function<? super V, ? extends K> keyMapper, Function<? super V, ? extends V> valueMapper){
		if(list != null && list.size() > 0){
			return list.stream().collect(toMap(keyMapper, valueMapper));
		}
		return null;
	}

	public static <K, V, U> Map<K, U> listToMap2(List<V> list, Function<? super V, ? extends K> keyMapper, Function<? super V, ? extends U> valueMapper){
		if(list != null && list.size() > 0){
			return list.stream().collect(toMap(keyMapper, valueMapper));
		}
		return null;
	}

	public static <K, V> Map<K, List<V>> listToMapList(List<V> list, Function<? super V, ? extends K> keyMapper){
		if(list != null && list.size() > 0){
			return streamToMapList(list.stream(), keyMapper);
		}
		return null;
	}

	public static <K, V> Map<K, Long> listToMapListCount(List<V> list, Function<? super V, ? extends K> keyMapper){
		if(list != null && list.size() > 0){
			return streamToMapListCount(list.stream(), keyMapper);
		}
		return null;
	}

	public static <K, V> Map<K, Double> listToMapListSumDouble(List<V> list, Function<? super V, ? extends K> keyMapper, ToDoubleFunction<? super V> mapper){
		if(list != null && list.size() > 0){
			return streamToMapListSumDouble(list.stream(), keyMapper, mapper);
		}
		return null;
	}

	public static <K, V, T> Map<K, List<T>> listToMapList(List<V> list, Function<? super V, ? extends K> keyMapper, Function<? super V, ? extends T> valueMapper){
		if(list != null && list.size() > 0){
			return streamToMapList(list.stream(), keyMapper, valueMapper);
		}
		return null;
	}
	
	public static <K, V, T> Map<K, List<T>> listToMapList(List<V> list, Supplier<Map<K, List<T>>> mapFactory, Function<? super V, ? extends K> keyMapper, Function<? super V, ? extends T> valueMapper){
		if(list != null && list.size() > 0){
			return streamToMapList(list.stream(), mapFactory, keyMapper, valueMapper);
		}
		return null;
	}
	
	public static <K, V, T> Map<K, List<T>> streamToMapList(Stream<V> stream, Supplier<Map<K, List<T>>> mapFactory, Function<? super V, ? extends K> keyMapper, Function<? super V, ? extends T> valueMapper){
		if(stream != null){
			return stream.collect(groupingBy(keyMapper, mapFactory, mapping(valueMapper, toList())));
		}
		return null;
	}

	public static <K, V> Map<K, List<V>> streamToMapList(Stream<V> stream, Function<? super V, ? extends K> keyMapper){
		if(stream != null){
			return stream.collect(groupingBy(keyMapper));
		}
		return null;
	}

	public static <K, V> Map<K, Long> streamToMapListCount(Stream<V> stream, Function<? super V, ? extends K> keyMapper){
		if(stream != null){
			return stream.collect(groupingBy(keyMapper, counting()));
		}
		return null;
	}

	public static <K, V> Map<K, Double> streamToMapListSumDouble(Stream<V> stream, Function<? super V, ? extends K> keyMapper, ToDoubleFunction<? super V> mapper){
		if(stream != null){
			return stream.collect(groupingBy(keyMapper, summingDouble(mapper)));
		}
		return null;
	}

	public static <K, V, T> Map<K, List<T>> streamToMapList(Stream<V> stream, Function<? super V, ? extends K> keyMapper, Function<? super V, ? extends T> valueMapper){
		if(stream != null){
			return stream.collect(groupingBy(keyMapper, mapping(valueMapper, toList())));
		}
		return null;
	}

	public static boolean isMap(Object obj) {
		return obj instanceof Map;
	}

	/**如果map里存在key，则执行f1，如果不存在key，则执行f2
	 * @param map
	 * @param key
	 * @param f1
	 * @param f2
	 */
	public static <K, V> void putIfAbsent(Map<K, V> map, K key, Function<? super K, ? extends V> f1, Function<? super K, ? extends V> f2) {
		if(map == null){
			return;
		}
		if(map.containsKey(key)){
			map.put(key, f1.apply(key));
		}else{
			map.put(key, f2.apply(key));
		}
	}

	/**合并map：把map2和map1里相同的key合并到map1，规则：如果map1里存在key，则执行f
	 * @param map1
	 * @param map2
	 * @param f(map2的key, map2的value)
	 * @return
	 */
	public static <K, V, U> Map<K, V> merge(Map<K, V> map1, Map<K, V> map2, BiFunction<K, V, V> f){
		if(map1 == null || map2 == null){
			return map1;
		}
		for(Entry<K, V> entry2 : map2.entrySet()) {
			K key = entry2.getKey();
			if(map1.containsKey(key)){
				map1.put(key, f.apply(entry2.getKey(), entry2.getValue()));
			}else{
				map1.put(key, entry2.getValue());
			}
		}
		return map1;
	}
	
	/**把key1,value1,key2,value2,key3,value3...转为Map<key, value>
	 * @param pairs
	 * @return
	 */
	public static Map<String, String> toStringMap(String... pairs) {
        Map<String, String> parameters = new HashMap<String, String>();
        if (pairs.length > 0) {
            if (pairs.length % 2 != 0) {
                throw new IllegalArgumentException("pairs must be even.");
            }
            for (int i = 0; i < pairs.length; i = i + 2) {
                parameters.put(pairs[i], pairs[i + 1]);
            }
        }
        return parameters;
    }
	

	/**
     * 获取map中第一个key值
     *
     * @param map 数据源
     * @return 
     */
    public static <K, V> K getFirstKeyOrNull(Map<K, V> map) {
    	if(isEmpty(map)){
    		return null;
    	}
    	K key = null;
        for (Entry<K, V> entry : map.entrySet()) {
        	key = entry.getKey();
            if (key != null) {
                break;
            }
        }
        return key;
    }
	
	
	/**
     * 获取map中第一个数据值
     *
     * @param map 数据源
     * @return 
     */
    public static <K, V> V getFirstValueOrNull(Map<K, V> map) {
    	if(isEmpty(map)){
    		return null;
    	}
    	V value = null;
        for (Entry<K, V> entry : map.entrySet()) {
            value = entry.getValue();
            if (value != null) {
                break;
            }
        }
        return  value;
    }

	/**map的value一个集合类型，把map按key，value展平
	 * @param aliases
	 */
	public static <K, V, C extends Collection<V>, R> Stream<TwoTuple<K, V>> flapMapMap(Map<K, C> aliases) {
		Stream<TwoTuple<K, C>> st = aliases.keySet().stream().map(indexName -> Tuple.tuple(indexName, aliases.get(indexName)));
		return st.flatMap(tuple -> {
    		K key = tuple.first;
    		C values = tuple.secord; // 集合
    		return values.stream().map(value -> Tuple.tuple(key, value));
    	});
	}

}
